/*
 * code based on libxfce4panel ( Copyright (c) 2005-2007 Jasper Huijsmans <jasper@xfce.org> )
 * modifications for use with rox-filer by rueldix@mail.ru
 *
 * Copyright notice:
 *
 * This library is free software; you can redistribute it and/or
 * modify it under the terms of the GNU Library General Public
 * License as published by the Free Software Foundation; either
 * version 2 of the License, or (at your option) any later version.
 *
 * This library is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 * Library General Public License for more details.
 *
 * You should have received a copy of the GNU Library General Public
 * License along with this library; if not, write to the
 * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
 * Boston, MA 02111-1307, USA.
 * 
 */
#include <gtk/gtk.h>
#include <stdlib.h>
#include <string.h>
#include <glib/gprintf.h>

#include "xfce-panel-plugin.h"
#ifdef ROX_PLUGIN_LENGTH_COMPATIBILITY
#include "xfce-fake.h"
#endif

#define ROX_PLUGIN_DEFAULT_WIDTH  (600)
#define ROX_PLUGIN_DEFAULT_HEIGHT (400)



#define XFCE_EXTERNAL_PANEL_PLUGIN_GET_PRIVATE(obj) (G_TYPE_INSTANCE_GET_PRIVATE ((obj), XFCE_EXTERNAL_PANEL_PLUGIN_TYPE, XfceExternalPanelPluginPrivate))

typedef struct _XfceExternalPanelPluginPrivate XfceExternalPanelPluginPrivate;

struct _XfceExternalPanelPluginPrivate
{
    gchar               *name;
    gchar               *id;
    gchar               *display_name;
    gint                 size;
#ifdef ROX_PLUGIN_SUPPORT_SCREEN_POSITION
    XfceScreenPosition   screen_position;
#endif
    XfceExternalPanelPluginFunc  construct;
    gulong               socket_id;
    GtkWidget           *menu;
    GdkWindow           *socket ; //? get_property??
    GSList              *menu_items;
#ifdef ROX_PLUGIN_LENGTH_COMPATIBILITY
    gint                 width;
    gint                 height;
#endif
    guint                config_status : 2; /* configure status: 0: nothing done yet, 1: read config file failed, 2: read config file successfully or signal already has been sent */
    guint                expand : 1;
    guint                show_configure : 1;
    guint                show_about : 1 ;
    guint                is_horizontal : 1 ;
    guint                menu_blocked : 1;
};


enum
{
#ifdef ROX_PLUGIN_SUPPORT_SCREEN_POSITION
    SCREEN_POSITION_CHANGED,
#endif
#ifdef SUPPORT_ORIENTATION_CHANGE
    ORIENTATION_CHANGED,
#endif
    SIZE_CHANGED,
#ifdef ROX_PLUGIN_SUPPORT_FREE_DATA
    FREE_DATA,
#endif
    SAVE,
    ABOUT,
    CONFIGURE,
    LAST_SIGNAL
};


enum
{
    PROP_0 = 0,
    PROP_NAME,
    PROP_ID,
    PROP_DISPLAY_NAME,
    PROP_SIZE,
#ifdef ROX_PLUGIN_SUPPORT_SCREEN_POSITION
    PROP_SCREEN_POSITION,
#endif
    PROP_EXPAND
};


typedef enum
{
    XFCE_PANEL_PLUGIN_CONSTRUCT = 0,
#ifdef ROX_PLUGIN_SUPPORT_FREE_DATA
    XFCE_PANEL_PLUGIN_FREE_DATA,
#endif
    XFCE_PANEL_PLUGIN_SAVE,
    XFCE_PANEL_PLUGIN_SIZE,
#ifdef ROX_PLUGIN_SUPPORT_SCREEN_POSITION
    XFCE_PANEL_PLUGIN_SCREEN_POSITION,
#endif
    XFCE_PANEL_PLUGIN_REMOVE,
    XFCE_PANEL_PLUGIN_EXPAND,
    XFCE_PANEL_PLUGIN_CUSTOMIZE,
    XFCE_PANEL_PLUGIN_MENU_DEACTIVATED,
    XFCE_PANEL_PLUGIN_POPUP_MENU,
    XFCE_PANEL_PLUGIN_CUSTOMIZE_ITEMS,
    XFCE_PANEL_PLUGIN_SENSITIVE,
    XFCE_PANEL_PLUGIN_MOVE,
    XFCE_PANEL_PLUGIN_FOCUS,
    XFCE_PANEL_PLUGIN_SET_HIDDEN
}
XfcePanelPluginMessage;


#ifdef ROX_PLUGIN_LENGTH_COMPATIBILITY

static void rox_properties_dialog(GtkWidget * button, XfcePanelPlugin *plugin);
static void save_compatibility_settings(XfcePanelPlugin *plugin);
static void load_compatibility_settings(XfceExternalPanelPlugin * plugin);

#define SIZE_REQUEST(plugin,priv)					\
    gtk_widget_set_size_request(GTK_WIDGET(plugin),			\
				(priv)->is_horizontal?priv->size:0,	\
				(priv)->is_horizontal?0:priv->size);
#else

#define SIZE_REQUEST(plugin,priv)					\
    gtk_widget_set_size_request(GTK_WIDGET(plugin),			\
				(priv)->is_horizontal?-1:0,		\
				(priv)->is_horizontal?0:-1);
#endif



static void xfce_external_panel_plugin_class_init (XfceExternalPanelPluginClass*);
static void xfce_external_panel_plugin_init (XfceExternalPanelPlugin*);
static void xfce_external_panel_plugin_get_property (GObject*, guint, GValue*, GParamSpec*);
static void xfce_external_panel_plugin_set_property (GObject*, guint, 
                                         const GValue*, GParamSpec*);

static gboolean _plugin_event_received (GtkWidget *win,GdkEventClient *ev,XfceExternalPanelPlugin *plugin);


static guint xfce_external_panel_plugin_signals[LAST_SIGNAL] = { 0 };




/* external */
/* BOOLEAN:INT (libxfce4panel-marshal.list:1) */
static void _libxfce4panel_marshal_BOOLEAN__INT (GClosure     *closure,
                                                 GValue       *return_value,
                                                 guint         n_param_values,
                                                 const GValue *param_values,
                                                 gpointer      invocation_hint,
                                                 gpointer      marshal_data) G_GNUC_INTERNAL;


#if GLIB_CHECK_VERSION(2,7,0)
#define PANEL_PARAM_READABLE  (G_PARAM_READABLE | G_PARAM_STATIC_NAME | G_PARAM_STATIC_NICK | G_PARAM_STATIC_BLURB)
/*#define PANEL_PARAM_WRITABLE  (G_PARAM_WRITABLE | G_PARAM_STATIC_NAME | G_PARAM_STATIC_NICK | G_PARAM_STATIC_BLURB)*/
#define PANEL_PARAM_READWRITE (G_PARAM_READWRITE | G_PARAM_STATIC_NAME | G_PARAM_STATIC_NICK | G_PARAM_STATIC_BLURB)
#else
#define PANEL_PARAM_READABLE  (G_PARAM_READABLE)
//#define PANEL_PARAM_WRITABLE  (G_PARAM_WRITABLE)
#define PANEL_PARAM_READWRITE (G_PARAM_READWRITE)
#endif





/* Get a GType that corresponds to X. The first time this function is
 * called (on object instantiation), the type is registered. */
GType
xfce_external_panel_plugin_get_type (void)
{
  static GType entry_type = 0;

  if (!entry_type)
  {
    static const GTypeInfo entry_info =  {
	sizeof (XfceExternalPanelPluginClass),
	NULL, 
	NULL,
	(GClassInitFunc) xfce_external_panel_plugin_class_init,
	NULL, 
	NULL,
	sizeof (XfceExternalPanelPlugin),
	0,
	(GInstanceInitFunc) xfce_external_panel_plugin_init,
    };
#ifdef DEBUG_NOT_APPLET
    entry_type = g_type_register_static (GTK_TYPE_WINDOW, "XfceExternalPanelPlugin", 
                                         &entry_info, 0);
#else
    entry_type = g_type_register_static (GTK_TYPE_PLUG, "XfceExternalPanelPlugin", 
                                         &entry_info, 0);
#endif
  }

  return entry_type;
}



static void
xfce_external_panel_plugin_set_name (XfceExternalPanelPlugin *plugin,
                                     const gchar             *name)
{
    XfceExternalPanelPluginPrivate *priv;
    priv = XFCE_EXTERNAL_PANEL_PLUGIN_GET_PRIVATE (plugin);
    g_free (priv->name);
    priv->name = g_strdup (name);
}



static void
xfce_external_panel_plugin_set_id (XfceExternalPanelPlugin *plugin,
                                   const gchar             *id)
{
    XfceExternalPanelPluginPrivate *priv;

    priv = XFCE_EXTERNAL_PANEL_PLUGIN_GET_PRIVATE (plugin);

    g_free (priv->id);
    priv->id = g_strdup (id);
}



static void
xfce_external_panel_plugin_set_display_name (XfceExternalPanelPlugin *plugin,
                                             const gchar             *name)
{
    XfceExternalPanelPluginPrivate *priv;

    priv = XFCE_EXTERNAL_PANEL_PLUGIN_GET_PRIVATE (plugin);

    g_free (priv->display_name);
    priv->display_name = g_strdup (name);
}






static void
xfce_external_panel_plugin_set_size (XfceExternalPanelPlugin *plugin,
                                     gint                     size)
{
    XfceExternalPanelPluginPrivate *priv;
    priv = XFCE_EXTERNAL_PANEL_PLUGIN_GET_PRIVATE (plugin);
    if (size != priv->size)
    {
	gboolean handled = FALSE;
	priv->size = size;
	g_signal_emit(plugin, xfce_external_panel_plugin_signals[SIZE_CHANGED], 0, size,&handled);
    }
}







static void
xfce_external_panel_plugin_finalize (GObject *object)
{
    XfceExternalPanelPluginPrivate *priv;
    priv = XFCE_EXTERNAL_PANEL_PLUGIN_GET_PRIVATE (object);
    //to do: update!
    g_free (priv->name);
    g_free (priv->id);
    g_free (priv->display_name);

}



static void
xfce_external_panel_plugin_set_property (GObject      *object,
                                         guint         prop_id,
                                         const GValue *value,
                                         GParamSpec   *pspec)
{
    (void)pspec;
    switch (prop_id)
    {
        case PROP_NAME:
            xfce_external_panel_plugin_set_name (
                XFCE_EXTERNAL_PANEL_PLUGIN (object),
                g_value_get_string (value));
            break;
        case PROP_ID:
            xfce_external_panel_plugin_set_id (
                XFCE_EXTERNAL_PANEL_PLUGIN (object),
                g_value_get_string (value));
            break;
        case PROP_DISPLAY_NAME:
            xfce_external_panel_plugin_set_display_name (
                XFCE_EXTERNAL_PANEL_PLUGIN (object),
                g_value_get_string (value));
        case PROP_SIZE:
            xfce_external_panel_plugin_set_size (
                XFCE_EXTERNAL_PANEL_PLUGIN (object),
                g_value_get_int (value));
            break;
#ifdef ROX_PLUGIN_SUPPORT_SCREEN_POSITION
        case PROP_SCREEN_POSITION:
            break;
#endif
        case PROP_EXPAND:
            break;
        default:
            G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
            break;
    }
}


static void
xfce_external_panel_plugin_get_property (GObject    *object,
                                         guint       prop_id,
                                         GValue     *value,
                                         GParamSpec *pspec)
{
    XfceExternalPanelPluginPrivate *priv;
    (void)pspec;
    priv = XFCE_EXTERNAL_PANEL_PLUGIN_GET_PRIVATE (object);

    switch (prop_id)
    {
        case PROP_NAME:
            g_value_set_static_string (value, priv->name);
            break;
        case PROP_ID:
            g_value_set_static_string (value, priv->id);
            break;
        case PROP_DISPLAY_NAME:
            g_value_set_static_string (value, priv->display_name);
            break;
        case PROP_SIZE:
            g_value_set_int (value, priv->size);
            break;
#ifdef ROX_PLUGIN_SUPPORT_SCREEN_POSITION
        case PROP_SCREEN_POSITION:
            g_value_set_enum (value, priv->screen_position);
            break;
#endif
        case PROP_EXPAND:
            g_value_set_boolean (value, priv->expand);
            break;
        default:
            G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
            break;
    }
}





/* Initialize the XfcePanelPluginClass class by overriding standard functions,
 * registering a private class and setting up signals and properties. */
static void
xfce_external_panel_plugin_class_init (XfceExternalPanelPluginClass *klass)
{
    GObjectClass *object_class;
    static gboolean initialized = FALSE;

    
    g_type_class_add_private (klass, sizeof (XfceExternalPanelPluginPrivate));

    object_class = G_OBJECT_CLASS (klass);
    object_class->finalize     = xfce_external_panel_plugin_finalize;
    object_class->get_property = xfce_external_panel_plugin_get_property;
    object_class->set_property = xfce_external_panel_plugin_set_property;

    if (G_UNLIKELY (!initialized))
    {

        /**
         * XfcePanelPlugin::size-changed
         * @plugin      : a #XfcePanelPlugin widget
         * @size        : new panel size
         *
         * Emitted when the panel size changes.
         *
         * Returns: %TRUE when handled, %FALSE otherwise.
         **/
        xfce_external_panel_plugin_signals [SIZE_CHANGED] =
            g_signal_new (I_("size-changed"),
                          G_TYPE_FROM_CLASS (klass),
                          G_SIGNAL_RUN_LAST | G_SIGNAL_NO_RECURSE | G_SIGNAL_NO_HOOKS,
                          0,
                          g_signal_accumulator_true_handled,
                          NULL,
                          _libxfce4panel_marshal_BOOLEAN__INT,
                          G_TYPE_BOOLEAN,
                          1, G_TYPE_INT);


        /**
         * XfcePanelPlugin::save
         * @plugin      : a #XfcePanelPlugin widget
         *
         * Emitted before the panel is closing. May be called more than once
         * while the panel is running. Plugin writers should connect to
         * this signal to save the plugins configuration.
         *
         * See also: xfce_external_panel_plugin_get_rc_file()
         **/
        xfce_external_panel_plugin_signals [SAVE] =
            g_signal_new (I_("save"),
                          G_TYPE_FROM_CLASS (klass),
                          G_SIGNAL_RUN_LAST | G_SIGNAL_NO_RECURSE | G_SIGNAL_NO_HOOKS,
                          0, NULL, NULL,
                          g_cclosure_marshal_VOID__VOID,
                          G_TYPE_NONE,
                          0);

        /**
         * XfcePanelPlugin::about
         * @plugin      : a #XfcePanelPlugin widget
         *
         * Emitted when the 'About' menu item is clicked. Plugin writers
         * should connect to this signal to show information about their
         * plugin (and its authors).
         *
         * See also: xfce_panel_plugin_menu_show_about()
         **/
        xfce_external_panel_plugin_signals [ABOUT] =
            g_signal_new (I_("about"),
                          G_TYPE_FROM_CLASS (klass),
                          G_SIGNAL_RUN_LAST | G_SIGNAL_NO_RECURSE | G_SIGNAL_NO_HOOKS,
                          0, NULL, NULL,
                          g_cclosure_marshal_VOID__VOID,
                          G_TYPE_NONE,
                          0);

        /**
         * XfcePanelPlugin::configure-plugin
         * @plugin      : a #XfcePanelPlugin widget
         *
         * Emitted when the 'Configure' menu item is clicked. Plugin writers
         * should connect to this signal to show a settings dialog.
         *
         * See also: xfce_panel_plugin_menu_show_configure()
         **/
        xfce_external_panel_plugin_signals [CONFIGURE] =
            g_signal_new (I_("configure-plugin"),
                          G_TYPE_FROM_CLASS (klass),
                          G_SIGNAL_RUN_LAST | G_SIGNAL_NO_RECURSE | G_SIGNAL_NO_HOOKS,
                          0, NULL, NULL,
                          g_cclosure_marshal_VOID__VOID,
                          G_TYPE_NONE,
                          0);

#ifdef ROX_PLUGIN_SUPPORT_SCREEN_POSITION
	/* signals that are never emmitted */
        xfce_external_panel_plugin_signals [SCREEN_POSITION_CHANGED] =
            g_signal_new (I_("screen-position-changed"),
                          G_TYPE_FROM_CLASS (klass),
                          G_SIGNAL_RUN_LAST | G_SIGNAL_NO_RECURSE | G_SIGNAL_NO_HOOKS,
                          0, NULL, NULL,
                          g_cclosure_marshal_VOID__ENUM,
                          G_TYPE_NONE,
                          1, XFCE_TYPE_SCREEN_POSITION);
#endif
#ifdef SUPPORT_ORIENTATION_CHANGE
        xfce_external_panel_plugin_signals [ORIENTATION_CHANGED] =
            g_signal_new (I_("orientation-changed"),
                          G_TYPE_FROM_CLASS (klass),
                          G_SIGNAL_RUN_LAST | G_SIGNAL_NO_RECURSE | G_SIGNAL_NO_HOOKS,
                          0, NULL, NULL,
                          g_cclosure_marshal_VOID__ENUM,
                          G_TYPE_NONE,
                          1, GTK_TYPE_ORIENTATION);
#endif
#ifdef ROX_PLUGIN_SUPPORT_FREE_DATA
        xfce_external_panel_plugin_signals [FREE_DATA] =
            g_signal_new (I_("free-data"),
                          G_TYPE_FROM_CLASS (klass),
                          G_SIGNAL_RUN_LAST | G_SIGNAL_NO_RECURSE | G_SIGNAL_NO_HOOKS,
                          0, NULL, NULL,
                          g_cclosure_marshal_VOID__VOID,
                          G_TYPE_NONE,
                          0);
#endif


        /**
         * XfcePanelPlugin:name
         *
         * Untranslated plugin name. This identifies the plugin type and
         * therefore has to be unique.
         **/
        g_object_class_install_property (object_class,PROP_NAME,
                                             g_param_spec_string ("name",
                                                                  "xfce_panel_plugin_name",
                                                                  "Plugin name",
                                                                  NULL,
                                                                  PANEL_PARAM_READABLE));

        /**
         * XfcePanelPlugin:id
         *
         * Unique identifier string created for every #XfcePanelPlugin instance.
         **/
        g_object_class_install_property (object_class,PROP_ID,
					 g_param_spec_string ("id",
							      "xfce_panel_plugin_id",
							      "Plugin id",
							      NULL,
							      PANEL_PARAM_READABLE));

        /**
         * XfcePanelPlugin:display-name
         *
         * Translated plugin name. This is the name that can be presented to
         * the user, e.g. in dialogs or menus.
         **/
        g_object_class_install_property (object_class,PROP_DISPLAY_NAME,
                                             g_param_spec_string ("display-name",
                                                                  "xfce_panel_plugin_display_name",
                                                                  "Plugin display name",
                                                                  NULL,
								  PANEL_PARAM_READABLE));
	/**
         * XfcePanelPlugin:size
         *
         * The current panel size.
         **/
        g_object_class_install_property (object_class, PROP_SIZE,
                                             g_param_spec_int ("size",
                                                               "xfce_panel_plugin_size",
                                                               "Panel size",
                                                               10, 128, 32,
                                                               PANEL_PARAM_READABLE));
   
#ifdef ROX_PLUGIN_SUPPORT_SCREEN_POSITION
        /**
         * XfcePanelPlugin:screen-position
         *
         * The current #XfceScreenPosition of the panel.
         **/
        g_object_class_install_property (object_class,PROP_SCREEN_POSITION,
					 g_param_spec_enum ("screen-position",
							    "xfce_panel_plugin_screen_position",
							    "Panel screen position",
							    XFCE_TYPE_SCREEN_POSITION,
							    XFCE_SCREEN_POSITION_S,
							    PANEL_PARAM_READABLE));
#endif
        /**
         * XfcePanelPlugin:expand
         *
         * Whether to expand the plugin when the panel width increases.
         **/
        g_object_class_install_property (object_class, PROP_EXPAND,
                                             g_param_spec_boolean ("expand",
                                                                   "xfce_panel_plugin_expand",
                                                                   "Whether to expand the plugin",
                                                                   FALSE,
                                                                   PANEL_PARAM_READWRITE));

        initialized = TRUE;
    }

}


GtkOrientation  xfce_panel_plugin_get_orientation(XfceExternalPanelPlugin *plugin){
    XfceExternalPanelPluginPrivate *priv = XFCE_EXTERNAL_PANEL_PLUGIN_GET_PRIVATE(plugin);
    return priv->is_horizontal ? GTK_ORIENTATION_HORIZONTAL : GTK_ORIENTATION_VERTICAL ;
}

#define STRINGIFY_REAL(s) #s
#define STRINGIFY(s) STRINGIFY_REAL(s)

gchar * xfce_panel_plugin_lookup_rc_file(XfceExternalPanelPlugin *plugin){
    XfceExternalPanelPluginPrivate *priv = XFCE_EXTERNAL_PANEL_PLUGIN_GET_PRIVATE(plugin);
    gchar *ret, *dir;
#ifdef DEBUG_NOT_APPLET
    char * tmp="debug_options.ini";
#else
    char tmp[sizeof STRINGIFY(UINT_MAX)];
    g_sprintf(tmp,"%u",g_str_hash(g_getenv("APP_DIR")));
#endif
    dir = g_build_path(G_DIR_SEPARATOR_S,g_get_user_config_dir(),ROX_PLUGIN_DOMAIN,ROX_PLUGIN_NAME,NULL);
    ret = g_mkdir_with_parents(dir,0700) != 0  ? NULL :
	g_build_path(G_DIR_SEPARATOR_S,g_get_user_config_dir(),ROX_PLUGIN_DOMAIN,ROX_PLUGIN_NAME,tmp,NULL);
    g_free(dir);
    if ( ret && priv->config_status == 0 ){
	if ( g_file_test(ret,G_FILE_TEST_EXISTS) ){
	    priv->config_status = 2 ;
	}
	else {
	    priv->config_status = 1 ;
	}
    }
    else {
	priv->config_status=1;
    }
    return ret;
}


gchar * xfce_panel_plugin_save_location(gpointer a, gboolean b){
    (void)b;
    return xfce_panel_plugin_lookup_rc_file(a);
}




static void
xfce_external_panel_plugin_init (XfceExternalPanelPlugin *plugin)
{
    XfceExternalPanelPluginPrivate *priv;
    priv = XFCE_EXTERNAL_PANEL_PLUGIN_GET_PRIVATE (plugin);
    priv->name            = NULL;
    priv->id              = NULL;
    priv->display_name    = NULL;
    priv->size            = -1;
#ifdef ROX_PLUGIN_SUPPORT_SCREEN_POSITION
    priv->screen_position = XFCE_SCREEN_POSITION_NONE;
#endif
    priv->construct       = NULL;
    priv->socket_id       = 0;
    priv->menu            = NULL;
    priv->socket          = NULL;
    priv->menu_items      = NULL;
    priv->config_status   = 0;
#ifdef ROX_PLUGIN_LENGTH_COMPATIBILITY
    priv->width= ROX_PLUGIN_DEFAULT_WIDTH;
    priv->height= ROX_PLUGIN_DEFAULT_HEIGHT;
#endif
    priv->expand          = 0;
    priv->show_configure  = 0;
    priv->show_about      = 0;
    priv->is_horizontal   = 1;
    priv->menu_blocked    = 0;
}


void xfce_panel_plugin_block_menu (XfceExternalPanelPlugin *plugin){
    XfceExternalPanelPluginPrivate *priv = XFCE_EXTERNAL_PANEL_PLUGIN_GET_PRIVATE(plugin);
    priv->menu_blocked=1;
}
void xfce_panel_plugin_unblock_menu (XfceExternalPanelPlugin *plugin){
    XfceExternalPanelPluginPrivate *priv = XFCE_EXTERNAL_PANEL_PLUGIN_GET_PRIVATE(plugin);
    priv->menu_blocked=0;
}


void xfce_panel_plugin_menu_show_configure(XfceExternalPanelPlugin *widget){
    XfceExternalPanelPlugin *plugin=XFCE_EXTERNAL_PANEL_PLUGIN(widget);
    XfceExternalPanelPluginPrivate *priv = XFCE_EXTERNAL_PANEL_PLUGIN_GET_PRIVATE(plugin);
    priv->show_configure=1;
}

void xfce_panel_plugin_menu_show_about(XfceExternalPanelPlugin *widget){
    XfceExternalPanelPlugin *plugin=XFCE_EXTERNAL_PANEL_PLUGIN(widget);
    XfceExternalPanelPluginPrivate *priv = XFCE_EXTERNAL_PANEL_PLUGIN_GET_PRIVATE(plugin);
    priv->show_about=1;
}


static void emit_configure(GtkWidget *widget,gpointer data){
    XfceExternalPanelPlugin *plugin=XFCE_EXTERNAL_PANEL_PLUGIN(data);
    (void)widget;
    g_signal_emit(plugin, xfce_external_panel_plugin_signals[CONFIGURE], 0);
}


#ifdef ROX_PLUGIN_SUPPORT_FREE_DATA
static void
emit_free_data(GtkWidget *widget,gpointer data)
{
    XfceExternalPanelPlugin *plugin=XFCE_EXTERNAL_PANEL_PLUGIN(data);
    g_signal_emit(plugin, xfce_external_panel_plugin_signals[FREE_DATA], 0);
    gtk_main_quit();
}
#endif


static void 
emit_save(GtkWidget *widget,gpointer data){
    XfceExternalPanelPlugin *plugin=XFCE_EXTERNAL_PANEL_PLUGIN(data);
    (void)widget;
#ifdef ROX_PLUGIN_LENGTH_COMPATIBILITY
    save_compatibility_settings(plugin);
#endif
    g_signal_emit(plugin, xfce_external_panel_plugin_signals[SAVE], 0);
}


static gboolean
rbutton_clicked (GtkWidget      *widget,
		 GdkEventButton *event,
		 gpointer        user_data)
{
    XfceExternalPanelPlugin *plugin=XFCE_EXTERNAL_PANEL_PLUGIN(user_data);
    XfceExternalPanelPluginPrivate *priv = XFCE_EXTERNAL_PANEL_PLUGIN_GET_PRIVATE(plugin);
    (void)widget;
    if (event->button != 3 || priv->menu_blocked ) {
	return FALSE;
    }

    if ( G_UNLIKELY(priv->menu == NULL ) ){
	GtkWidget * quit;
	priv->menu=gtk_menu_new ();
	gtk_menu_attach_to_widget(GTK_MENU(priv->menu), GTK_WIDGET(plugin), NULL);
	
	if ( priv->menu_items ){
	    GSList * b ;
	    GtkWidget* seperator ;
	    for ( b = priv->menu_items ; b ; b = b->next ){
		GtkWidget * menu_item = b->data;
		gtk_menu_shell_append (GTK_MENU_SHELL(priv->menu),menu_item);
	    }
	    seperator = gtk_separator_menu_item_new();
	    gtk_menu_shell_append (GTK_MENU_SHELL(priv->menu),seperator);
	}
	
#ifdef ROX_PLUGIN_LENGTH_COMPATIBILITY
	do {
	    GtkWidget * rox_configure = gtk_image_menu_item_new_with_label("rox compatibility");
	    gtk_widget_show(rox_configure);
	    g_signal_connect (G_OBJECT (rox_configure), "activate",
			      G_CALLBACK (rox_properties_dialog), plugin);
  	    gtk_menu_shell_append (GTK_MENU_SHELL(priv->menu),rox_configure);
	} while(0);	
#endif

	if ( priv->show_configure ){
	    GtkWidget * configure = gtk_image_menu_item_new_from_stock (GTK_STOCK_PREFERENCES, NULL);
	    gtk_widget_show(configure);
	    g_signal_connect (G_OBJECT (configure), "activate",
			      G_CALLBACK (emit_configure), plugin);
  	    gtk_menu_shell_append (GTK_MENU_SHELL(priv->menu),configure);
	}

	quit = gtk_image_menu_item_new_from_stock (GTK_STOCK_QUIT, NULL);
	gtk_widget_show (quit);
#ifdef ROX_PLUGIN_SUPPORT_FREE_DATA
	g_signal_connect (G_OBJECT(quit), "activate",
			  G_CALLBACK (emit_free_data), plugin);
#else
	g_signal_connect (G_OBJECT(quit), "activate",
			  G_CALLBACK (gtk_main_quit), NULL);
#endif
	gtk_menu_shell_append (GTK_MENU_SHELL(priv->menu),quit);
	gtk_widget_show_all(priv->menu);

	g_signal_connect(GTK_WIDGET(priv->menu), "remove",
			 G_CALLBACK(emit_save), plugin);

    }
    gtk_menu_popup(GTK_MENU(priv->menu), NULL, NULL, NULL, NULL, 
		   event->button, event->time);
    return FALSE; /* return TRUE, what does plugins expect?? */
}


/*
read_property,read_string and code of getsize are taken from Tasklist
*/


/* Read the contents of this property. g_free() the result. */
static char *read_property(GdkWindow *window, GdkAtom prop,
			   GdkAtom type, gsize *out_length)
{
    gsize	grab_len = 4096;
    gint	length;
    guchar	*data;
    
    while (1)
    {
	if (!(gdk_property_get(window, prop, type, 0, grab_len,
			       FALSE, NULL, NULL, &length, &data) && data))
	  return NULL;	/* Error? */
	
	if ((gsize)length >= grab_len)
	{
	    /* Didn't get all of it - try again */
	    grab_len <<= 1;
	    g_free(data);
	    continue;
	}
	
	*out_length = (gsize)length;
	
	return (char *) data;
    }
}


static char *read_string(GdkWindow *window, GdkAtom prop)
{
    gsize  len;
    gchar *data;
    
    data = read_property(window, prop,
			 gdk_atom_intern("STRING", FALSE), &len);
    
    if (!data)
      return NULL;
    
    data = g_realloc(data, len + 1);
    data[len] = '\0';
    return data;
}


static void get_size(XfceExternalPanelPlugin *plugin, int * width, int * height, gboolean * is_horizontal){
    XfceExternalPanelPluginPrivate *priv = XFCE_EXTERNAL_PANEL_PLUGIN_GET_PRIVATE(plugin);
    gdk_window_get_geometry(priv->socket,NULL,NULL,width,height,NULL);
    if ( is_horizontal ){
	gchar *pos;
	*is_horizontal=TRUE;
	pos = read_string(priv->socket,
			  gdk_atom_intern("_ROX_PANEL_MENU_POS", FALSE));
	if ( pos ){
	    if (!strncmp(pos, "Left", 4) || !strncmp(pos, "Righ", 4)){
		*is_horizontal=FALSE;
	    }
	    else {
		*is_horizontal=TRUE;
	    }
	    g_free(pos);
	}
    }
}



/* Create and return a new instance of the XfcePanelPlugin widget. */
GtkWidget*
xfce_external_panel_plugin_new(gint argc,
			       gchar **argv,
			       XfceExternalPanelPluginFunc construct)
{
    XfceExternalPanelPlugin                *plugin;
    XfceExternalPanelPluginPrivate *priv;
    gboolean horizontal;
#ifndef DEBUG_NOT_APPLET
    //int width, height;
    if (argc < 2){
	return NULL;
    }
#endif
    plugin = g_object_new (XFCE_EXTERNAL_PANEL_PLUGIN_TYPE, NULL);
    priv = XFCE_EXTERNAL_PANEL_PLUGIN_GET_PRIVATE (plugin);
    priv->construct = construct;
    priv->name = g_strdup (ROX_PLUGIN_NAME);
    priv->display_name=g_strdup(ROX_PLUGIN_DISPLAY_NAME);
    priv->menu_items = NULL;
#ifndef DEBUG_NOT_APPLET
    priv->socket_id = strtoul (argv[1], NULL, 0);
    priv->id = g_strdup_printf("%"G_GSIZE_FORMAT,(gsize)priv->socket_id);
    priv->socket = gdk_window_foreign_new(priv->socket_id);
    if ( ! priv->socket ){
	gtk_widget_destroy (GTK_WIDGET (plugin));
	return NULL;
    }
    get_size(plugin,NULL,NULL,&horizontal);
    priv->is_horizontal = horizontal ? 1 : 0;
#ifdef ROX_PLUGIN_LENGTH_COMPATIBILITY 
    load_compatibility_settings(plugin);
    priv->size=horizontal ? priv->width : priv->height;
#endif
    SIZE_REQUEST(plugin,priv);

#else /* #ifndef DEBUG_NOT_APPLET */
    priv->id = g_strdup("123");
    priv->is_horizontal=0;
#ifdef ROX_PLUGIN_LENGTH_COMPATIBILITY 
    load_compatibility_settings(plugin);
    priv->size=horizontal ? priv->width : priv->height;
#else
    priv->size=48;
#endif
    gtk_widget_set_size_request(GTK_WIDGET(plugin),48,48);

#endif

#ifndef DEBUG_NOT_APPLET
    gtk_plug_construct (GTK_PLUG (plugin), priv->socket_id);
#endif
    //priv->menu = NULL;

    g_signal_connect (G_OBJECT (plugin), "button-press-event",
		      G_CALLBACK(rbutton_clicked), plugin);

    g_signal_connect (G_OBJECT (plugin), "configure-event",
		      G_CALLBACK (_plugin_event_received), plugin); 

    priv->construct(plugin);

    if ( priv->config_status == 1 ){
	emit_configure(GTK_WIDGET(plugin),plugin);
	priv->config_status=2;
    }

    gtk_widget_show (GTK_WIDGET (plugin));
    return GTK_WIDGET (plugin);
}


#ifdef ROX_PLUGIN_SUPPORT_SCREEN_POSITION
GType
xfce_screen_position_get_type (void)
{
	static GType type = 0;
	if (type == 0) {
	static const GEnumValue values[] = {
	{ XFCE_SCREEN_POSITION_NONE, "XFCE_SCREEN_POSITION_NONE", "none" },
	{ XFCE_SCREEN_POSITION_NW_H, "XFCE_SCREEN_POSITION_NW_H", "nw-h" },
	{ XFCE_SCREEN_POSITION_N, "XFCE_SCREEN_POSITION_N", "n" },
	{ XFCE_SCREEN_POSITION_NE_H, "XFCE_SCREEN_POSITION_NE_H", "ne-h" },
	{ XFCE_SCREEN_POSITION_NW_V, "XFCE_SCREEN_POSITION_NW_V", "nw-v" },
	{ XFCE_SCREEN_POSITION_W, "XFCE_SCREEN_POSITION_W", "w" },
	{ XFCE_SCREEN_POSITION_SW_V, "XFCE_SCREEN_POSITION_SW_V", "sw-v" },
	{ XFCE_SCREEN_POSITION_NE_V, "XFCE_SCREEN_POSITION_NE_V", "ne-v" },
	{ XFCE_SCREEN_POSITION_E, "XFCE_SCREEN_POSITION_E", "e" },
	{ XFCE_SCREEN_POSITION_SE_V, "XFCE_SCREEN_POSITION_SE_V", "se-v" },
	{ XFCE_SCREEN_POSITION_SW_H, "XFCE_SCREEN_POSITION_SW_H", "sw-h" },
	{ XFCE_SCREEN_POSITION_S, "XFCE_SCREEN_POSITION_S", "s" },
	{ XFCE_SCREEN_POSITION_SE_H, "XFCE_SCREEN_POSITION_SE_H", "se-h" },
	{ XFCE_SCREEN_POSITION_FLOATING_H, "XFCE_SCREEN_POSITION_FLOATING_H", "floating-h" },
	{ XFCE_SCREEN_POSITION_FLOATING_V, "XFCE_SCREEN_POSITION_FLOATING_V", "floating-v" },
	{ 0, NULL, NULL }
	};
	type = g_enum_register_static ("XfceScreenPosition", values);
  }
	return type;
}
#endif


#ifdef G_ENABLE_DEBUG
#define g_marshal_value_peek_int(v)      g_value_get_int (v)
#else /* !G_ENABLE_DEBUG */
/* WARNING: This code accesses GValues directly, which is UNSUPPORTED API.
 *          Do not access GValues directly in your code. Instead, use the
 *          g_value_get_*() functions
 */
#define g_marshal_value_peek_int(v)      (v)->data[0].v_int
#endif /* !G_ENABLE_DEBUG */



/* BOOLEAN:INT (libxfce4panel-marshal.list:1) */
void
_libxfce4panel_marshal_BOOLEAN__INT (GClosure     *closure,
                                     GValue       *return_value G_GNUC_UNUSED,
                                     guint         n_param_values,
                                     const GValue *param_values,
                                     gpointer      invocation_hint G_GNUC_UNUSED,
                                     gpointer      marshal_data)
{
  typedef gboolean (*GMarshalFunc_BOOLEAN__INT) (gpointer     data1,
                                                 gint         arg_1,
                                                 gpointer     data2);
  register GMarshalFunc_BOOLEAN__INT callback;
  register GCClosure *cc = (GCClosure*) closure;
  register gpointer data1, data2;
  gboolean v_return;

  g_return_if_fail (return_value != NULL);
  g_return_if_fail (n_param_values == 2);

  if (G_CCLOSURE_SWAP_DATA (closure))
    {
      data1 = closure->data;
      data2 = g_value_peek_pointer (param_values + 0);
    }
  else
    {
      data1 = g_value_peek_pointer (param_values + 0);
      data2 = closure->data;
    }
  callback = (GMarshalFunc_BOOLEAN__INT) (marshal_data ? marshal_data : cc->callback);

  v_return = callback (data1,
                       g_marshal_value_peek_int (param_values + 1),
                       data2);

  g_value_set_boolean (return_value, v_return);
}




static gboolean
_plugin_event_received (GtkWidget               *win,
                        GdkEventClient          *ev,
                        XfceExternalPanelPlugin *pluginr)
{
    gboolean handled = FALSE;
    XfceExternalPanelPlugin *plugin=XFCE_EXTERNAL_PANEL_PLUGIN(pluginr); /* ? */
    XfceExternalPanelPluginPrivate *priv = XFCE_EXTERNAL_PANEL_PLUGIN_GET_PRIVATE(plugin);
    int size;
    (void)win;
    (void)ev;
    get_size(plugin,NULL,priv->is_horizontal? &size : NULL, priv->is_horizontal ? NULL : &size );
    SIZE_REQUEST(plugin,priv);
    g_signal_emit(plugin, xfce_external_panel_plugin_signals[SIZE_CHANGED], 0, size ,&handled);
    return FALSE;
}


GtkWidget*    xfce_hvbox_new                      (GtkOrientation orientation,
                                                         gboolean homogeneous,
						   gint spacing){
    return orientation == GTK_ORIENTATION_VERTICAL ?
	gtk_vbox_new(homogeneous,spacing) :
	gtk_hbox_new(homogeneous,spacing) ;
}


/**
 * xfce_panel_plugin_add_action_widget:
 * @plugin : a #XfcePanelPlugin
 * @widget : a #GtkWidget that receives mouse events
 *
 * Attach the plugin menu to this widget. Plugin writers should call this
 * for every widget that can receive mouse events. If you forget to call this
 * the plugin will not have a right-click menu and the user won't be able to
 * remove it.
 **/
void
xfce_panel_plugin_add_action_widget (XfceExternalPanelPlugin *plugin,
                                     GtkWidget       *widget)
{
    g_signal_connect (G_OBJECT (widget), "button-press-event",
		      G_CALLBACK ( rbutton_clicked ), plugin);

}


void  xfce_panel_plugin_menu_insert_item(XfceExternalPanelPlugin *plugin, GtkMenuItem *item){
    XfceExternalPanelPluginPrivate *priv= XFCE_EXTERNAL_PANEL_PLUGIN_GET_PRIVATE (plugin);
    priv->menu_items=g_slist_prepend(priv->menu_items,item);
}

gint  xfce_panel_plugin_get_size(XfceExternalPanelPlugin *plugin){
    XfceExternalPanelPluginPrivate *priv= XFCE_EXTERNAL_PANEL_PLUGIN_GET_PRIVATE (plugin);
    return priv->size;
}



#ifdef ROX_PLUGIN_LENGTH_COMPATIBILITY


static void
load_compatibility_settings(XfceExternalPanelPlugin * plugin)
{
    char *file;
    XfceRc *rc;
    XfceExternalPanelPluginPrivate *priv = XFCE_EXTERNAL_PANEL_PLUGIN_GET_PRIVATE(plugin);
    if ((file = xfce_panel_plugin_lookup_rc_file (plugin)) != NULL)
    {
        rc = xfce_rc_simple_open (file, TRUE);
        g_free (file);
        if (rc != NULL)
        {
	    priv->width = xfce_rc_read_int_entry (rc, "rox_plugin_width", ROX_PLUGIN_DEFAULT_WIDTH);
	    priv->height =xfce_rc_read_int_entry (rc, "rox_plugin_height", ROX_PLUGIN_DEFAULT_HEIGHT);
	    priv->config_status=0;
	    xfce_rc_close (rc);
	}
    }
}


static void
save_compatibility_settings(XfcePanelPlugin *plugin)
{
    XfceExternalPanelPluginPrivate *priv = XFCE_EXTERNAL_PANEL_PLUGIN_GET_PRIVATE(plugin);
    char *file;
    XfceRc *rc;

    if (!(file = xfce_panel_plugin_save_location (plugin, TRUE)))
        return;

    rc = xfce_rc_simple_open (file, FALSE);
    g_free (file);

    if (!rc)
        return;

    xfce_rc_write_int_entry (rc, "rox_plugin_width", priv->width);
    xfce_rc_write_int_entry (rc, "rox_plugin_height", priv->height);

    xfce_rc_close (rc);
}



/* -------------------------------------------------------------------- *
 *                        Configuration Dialog                          *
 * -------------------------------------------------------------------- */

typedef struct dialog_data {
    GtkWidget * cb;
    GtkWidget * sp;
    XfcePanelPlugin *plugin;
} dialog_data;

static void
toggled(GtkToggleButton *tb, dialog_data * data)
{
    XfceExternalPanelPluginPrivate *priv = XFCE_EXTERNAL_PANEL_PLUGIN_GET_PRIVATE(data->plugin);
    gboolean a =!GTK_WIDGET_IS_SENSITIVE(data->sp);
    gtk_widget_set_sensitive(data->sp,a);
    (void)tb;
    if ( ! a ){
	priv->size=-1;
    }
    else {
	priv->size = gtk_spin_button_get_value_as_int(GTK_SPIN_BUTTON(data->sp));
    }
    *(priv->is_horizontal ? &priv->width : &priv->height )=priv->size;
    a=FALSE;
    SIZE_REQUEST(data->plugin,priv);
}

static void
spinbox_changed (GtkSpinButton  *sb, dialog_data * data)
{
    XfceExternalPanelPluginPrivate *priv = XFCE_EXTERNAL_PANEL_PLUGIN_GET_PRIVATE(data->plugin);
    gboolean handled=FALSE;
    priv->size = gtk_spin_button_get_value_as_int(sb);
    *(priv->is_horizontal ? &priv->width : &priv->height )=priv->size;
    SIZE_REQUEST(data->plugin,priv);
    g_signal_emit(data->plugin, xfce_external_panel_plugin_signals[SIZE_CHANGED], 0, 0 , &handled);
}



static void
rox_plugin_dialog_response (GtkWidget *dlg, int reponse,
			    dialog_data * data)
{
    if ( G_LIKELY(reponse == GTK_RESPONSE_OK) ){
	save_compatibility_settings(data->plugin);
    }
    gtk_widget_destroy(dlg);
    xfce_panel_plugin_unblock_menu(data->plugin);
    g_slice_free(dialog_data,data);
}


static void
rox_plugin_dialog_destroy(GtkWidget *dlg, int response,
			  dialog_data * data){
    (void)dlg;
    (void)response;
    xfce_panel_plugin_unblock_menu(data->plugin);
    g_slice_free(dialog_data,data);
}



static void
    rox_properties_dialog(GtkWidget *button, XfcePanelPlugin * plugin)
{
    GtkWidget *dlg, *vbox;
    dialog_data * data = g_slice_new(dialog_data);
    //*cb, *sp;
    XfceExternalPanelPluginPrivate *priv = XFCE_EXTERNAL_PANEL_PLUGIN_GET_PRIVATE(plugin);
    data->plugin=plugin;
    (void)button;
    xfce_panel_plugin_block_menu(plugin);
    
    dlg = xfce_titled_dialog_new_with_buttons ("Rox Plugin Configuration", NULL,
					       GTK_DIALOG_DESTROY_WITH_PARENT | GTK_DIALOG_NO_SEPARATOR,
					       GTK_STOCK_CLOSE, GTK_RESPONSE_OK,
					       NULL);
    
    gtk_window_set_screen (GTK_WINDOW (dlg),
                           gtk_widget_get_screen (GTK_WIDGET (plugin)));
    
    g_object_set_data (G_OBJECT (plugin), "dialog", dlg);
    
    gtk_window_set_position (GTK_WINDOW (dlg), GTK_WIN_POS_CENTER);
    gtk_window_set_icon_name (GTK_WINDOW (dlg), GTK_STOCK_PROPERTIES);

    g_signal_connect (dlg, "response", G_CALLBACK (rox_plugin_dialog_response),data);
    g_signal_connect (dlg, "close", G_CALLBACK (rox_plugin_dialog_destroy),data);
    
    vbox = gtk_vbox_new (FALSE, 6);
    gtk_container_set_border_width (GTK_CONTAINER (vbox), 6);
    gtk_widget_show (vbox);
    gtk_box_pack_start (GTK_BOX (GTK_DIALOG (dlg)->vbox), vbox,
                        TRUE, TRUE, 0);
    
    data->cb = gtk_check_button_new_with_mnemonic (priv->is_horizontal ? "fixed _width:" : "fixed _height:" );
    gtk_widget_show (data->cb);
    gtk_box_pack_start (GTK_BOX (vbox), data->cb, FALSE, FALSE, 0);
    
    if ( priv->is_horizontal ){
	data->sp = gtk_spin_button_new_with_range (100,4000,10);
	gtk_spin_button_set_value(GTK_SPIN_BUTTON(data->sp), priv->width == -1 ? ROX_PLUGIN_DEFAULT_WIDTH : priv->width);
    }
    else {
	data->sp = gtk_spin_button_new_with_range (100,4000,10);
	gtk_spin_button_set_value(GTK_SPIN_BUTTON(data->sp), priv->height== -1 ? ROX_PLUGIN_DEFAULT_HEIGHT : priv->height );
    }
    
    gtk_widget_show (data->sp);
    gtk_box_pack_start (GTK_BOX (vbox), data->sp, FALSE, FALSE, 0);
    
    if ( priv->size != -1 ){
	gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON (data->cb),TRUE);
	gtk_widget_set_sensitive(data->sp,TRUE);
    }
    else {
	gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON (data->cb),FALSE);
	gtk_widget_set_sensitive(data->sp,FALSE);
    }
    
    g_signal_connect (G_OBJECT(data->cb), "toggled", G_CALLBACK (toggled),data);
    g_signal_connect (G_OBJECT (data->sp),"value-changed",G_CALLBACK(spinbox_changed), data);
    
    gtk_widget_show (dlg);
}
#endif
